﻿
using com.iot.core.boot;
using com.iot.core.boot.configuration;
using com.iot.core.exception;
using com.iot.core.ext;
using com.iot.core.infrastructure;
using com.iot.core.manager.htcls;
using com.iot.core.manager.id;
using com.iot.core.util;
using Microsoft.EntityFrameworkCore;
 
using System.Linq.Expressions;
using System.Reflection;
using com.iot.core.ext;
using System.Linq.Dynamic.Core;
using Icom.iot.core.ext;
using com.iot.core.data.entity;

namespace com.iot.core.data
{
    public partial class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
    {
        IotDbContext _DB=null;
        public Repository(IotDbContext DB1 )
        {
            _DB = DB1;// EngineContext.Current.Resolve< IotDbContext>();

        }

        public IotDbContext DB
        {
            get {
                  
                return _DB;
             }
        }
        public IQueryable<TEntity> GetAll(bool includeDeleted = false)
        {
            var query= DB.Set<TEntity>().AsQueryable();
            
            if (typeof(TEntity).GetInterface(nameof(ISoftDeletedEntity)) == null)
                return query;
            if (includeDeleted)
            {
                return query;
            }
            return query.OfType<ISoftDeletedEntity>().Where(entry => !entry.Deleted).OfType<TEntity>();
                        
        }
        public Task<int>  SaveChagnesAsync()
        { 
                return DB.SaveChangesAsync();
        }
       
        public int SaveChagnes()
        {
         
            return DB.SaveChanges();
        }
        public    TEntity  GetById(long id)
        {
            var m =   GetAll().Where(a => a.Id == id).FirstOrDefault();
            return m;
        }
      
        public async Task<TEntity> GetByIdAsync(long id)
        {
            var m = await GetAll().Where(a => a.Id == id).FirstOrDefaultAsync();
            return m;
        }
        public TEntity GetById(BaseQto qm)
        {
            return GetById(qm.Id);
        }


        public   List<TEntity> GetByIds(List<long> lid)
        {
            var l =   GetAll().Where(a => lid.Contains(a.Id)).ToList();
            return l;
        }
        public async Task<List<TEntity>> GetByIdsAsync(List<long> lid)
        {
            var l = await GetAll().Where(a => lid.Contains(a.Id)).ToListAsync();
            return l;
        }


        public void Insert(TEntity entity, bool autoField = true)
        {
            if (DB.Entry<TEntity>(entity).State == EntityState.Detached)
            {
                DB.Set<TEntity>().Add(entity);
            }
            if (autoField)
            {
                var iotHttpContext = EngineContext.Current.Resolve<MyContext>();
                if(iotHttpContext==null|| iotHttpContext.Su == null)
                {
                    
                }
                else
                {
                    HtClsManager.Current.SetFieldV(entity, "CrtDt", DateTime.Now);
                    HtClsManager.Current.SetFieldV(entity, "CrtUid", iotHttpContext.Su.CrtUid);
                    HtClsManager.Current.SetFieldV(entity, "CrtDid", iotHttpContext.Su.CrtDid);
                    HtClsManager.Current.SetFieldV(entity, "Gid", HtIdManager.Current.NextGuid());


                    HtClsManager.Current.SetFieldV(entity, "EdtDt", DateTime.Now);
                    HtClsManager.Current.SetFieldV(entity, "EdtUid", iotHttpContext.Su.CrtUid);
                }
                 
            }

        }

        public void Update(TEntity entity, bool autoField = true)
        {
            if (DB.Entry<TEntity>(entity).State == EntityState.Detached)
            {
                DB.Entry<TEntity>(entity).State = EntityState.Modified;
            }

            if (autoField)
            {
                var iotHttpContext = EngineContext.Current.Resolve<MyContext>();
                if (iotHttpContext == null || iotHttpContext.Su == null)
                {

                }
                else
                {
                    HtClsManager.Current.SetFieldV(entity, "EdtDt", DateTime.Now);
                    HtClsManager.Current.SetFieldV(entity, "EdtUid", iotHttpContext.Su.CrtUid);
                }


            }

        }

        public void Delete(TEntity entity, bool autoField = true)
        {
            if (autoField)
            {
                var iotHttpContext = EngineContext.Current.Resolve<MyContext>();
                if (iotHttpContext == null || iotHttpContext.Su == null)
                {

                }
                else
                {
                    HtClsManager.Current.SetFieldV(entity, "EdtDt", DateTime.Now);
                    HtClsManager.Current.SetFieldV(entity, "EdtUid", iotHttpContext.Su.CrtUid);
                }

            }

            if (DB.Entry<TEntity>(entity).State == EntityState.Detached)
            {
                DB.Entry<TEntity>(entity).State = EntityState.Deleted;
                if (typeof(TEntity).GetInterface(nameof(ISoftDeletedEntity)) == null)
                {
                   
                }
                else
                {
                    (entity as ISoftDeletedEntity).Deleted = true;
                }                
            }
            else
            {
                if (typeof(TEntity).GetInterface(nameof(ISoftDeletedEntity)) == null)
                {
                    DB.Set<TEntity>().Remove(entity);
                }
                else
                {
                    (entity as ISoftDeletedEntity).Deleted = true;
                }
                 
            }

            

        }

        public void Detach(TEntity entity)
        {
            if (DB.Entry<TEntity>(entity).State != EntityState.Detached)
            {
                DB.Entry<TEntity>(entity).State = EntityState.Detached;
            }
        }


        public List<T> QueryToList<T>(string sql, int CommandTimeout = 30) where T:new()
        { 

            var _DBConnCfg = Singleton<AppSettings>.Instance.Get<DBConnCfg>();
            var connstr = _DBConnCfg.ConnectionString;
            switch (_DBConnCfg.DataProvider)
            {
                case "mysql":
                    return MysqlHelper.QueryToList<T>(connstr, sql, CommandTimeout);
                   
                case "sqllite":
                    return SqlLiteHelper.QueryToList<T>(connstr, sql, CommandTimeout);
                    
                default:
                    throw new MyException("暂时未实现的数据库");
            }
             
        }
        public List<IdNameDto> QueryName(List<long> lid,string tbname="",string namefiled="")
        {
            if (lid.Count == 0)
            {
                return new List<IdNameDto>();
            }
            if (string.IsNullOrEmpty(tbname  ))
            {
                tbname = typeof(TEntity).Name;
            }
            if (string.IsNullOrEmpty(namefiled))
            {
                namefiled = "Name";
            }
            var sids = StringUtil.Join(lid);
            var sql = $"select id,{namefiled} as Name from {tbname} where id in ({sids})";
            return QueryToList<IdNameDto>(sql);
        }
        public string GetName(long id, string tbname = "", string namefiled = "")
        {
            if (string.IsNullOrEmpty(tbname))
            {
                tbname = typeof(TEntity).Name;
            }
            if (string.IsNullOrEmpty(namefiled))
            {
                namefiled = "Name";
            }
            var sql = $"select id,{namefiled} as Name from {tbname} where id={id}";
            var l= QueryToList<IdNameDto>(sql);
            if (l.Count > 0)
            {
                return l[0].Name??"";
            }
            return "";
        }

        public void EntityToDto(object src, object dst)
        {
            if (src == null|| dst==null)
            {
                throw new MyException("不支持的对象");
            }
            var msrccls = HtClsManager.Current.FindByFullName(src.GetType().FullName);
            if(msrccls == null)
            {
                throw new MyException("不支持的对象");
            }
            var mdstcls = HtClsManager.Current.FindByFullName(dst.GetType().FullName);
            if (mdstcls == null)
            {
                throw new MyException("不支持的对象");
            }

            foreach(var pdst in mdstcls.Fields)
            {
                var psrc=msrccls.Fields.Where(a=>a.Ename==pdst.Ename).FirstOrDefault();
                if(psrc == null)
                {
                    continue;
                }
                if(pdst.Ename.ToUpper() == "PWD"|| pdst.Ename.ToUpper() == "CZPWD")
                {
                    continue;
                }
                var vsrc = psrc.Field.GetValue(src, null);
                if (vsrc == null)
                {
                    continue;//null 强制跳过
                }
                pdst.Field.SetValue(dst, ConvertHelper.ChangeType(vsrc, pdst.Field.PropertyType), null);
            }


        }

        
        public void DtoToEntity(object src, object dst)
        {
            if (src == null || dst == null)
            {
                throw new MyException("不支持的对象");
            }
            var msrccls = HtClsManager.Current.FindByFullName(src.GetType().FullName);
            if (msrccls == null)
            {
                throw new MyException("不支持的对象");
            }
            var mdstcls = HtClsManager.Current.FindByFullName(dst.GetType().FullName);
            if (mdstcls == null)
            {
                throw new MyException("不支持的对象");
            }

            foreach (var pdst in mdstcls.Fields)
            {
                //插入 、修改时间不能更新
                if (pdst.Ename.ToLower().StartsWith("crtdt"))
                {
                    continue;
                }
                if (pdst.Ename.ToLower().StartsWith("edtdt"))
                {
                    continue;
                }
                var psrc = msrccls.Fields.Where(a => a.Ename == pdst.Ename).FirstOrDefault();
                if (psrc == null)
                {
                    continue;
                }
                if (pdst.Ename.ToUpper() == "PWD" || pdst.Ename.ToUpper() == "CZPWD")
                {
                    continue;
                }
                var vsrc = psrc.Field.GetValue(src, null);
                if (vsrc == null&&!pdst.Nullable)
                {
                    continue;//null 强制跳过
                }
                if (pdst.Ename.ToLower().Equals("id"))
                {
                    if (vsrc.ToString()=="0")
                    {
                        vsrc = (Int64)(HtIdManager.Current.NextLong());
                    }
                }

                pdst.Field.SetValue(dst, ConvertHelper.ChangeType(vsrc, pdst.Field.PropertyType), null);
            }
        }

        public IQueryable<TEntity> Sort(IQueryable<TEntity> q, Sort sort)
        { 
            if (sort == null||string.IsNullOrEmpty(sort.Filed) )
            {
                sort = new Sort { Filed = "Id", Asc = true };
            }
            var property = typeof(TEntity).GetProperty(sort.Filed, BindingFlags.IgnoreCase);
            if (property != null)
            {
                return q.OrderBy(a => a.Id);
            }
             
            var parameter = Expression.Parameter(typeof(TEntity), "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);
            if (sort.Asc)
            {
                return q.OrderBy(a=>property.GetValue(a,null) );
            }
            else
            {
                return q.OrderByDescending(a => property.GetValue(a, null));
            }

             
        }

        public   Page<TEntity> Page(IQueryable<TEntity> q, BasePageQto qm)
        {
            var Total =   q.Count();
            var r = new Page<TEntity>(Total, qm.Page, qm.PageSize);

            var l =   q.SortPageTake(qm.GetSort(), r);
            r.Records = l;
            return r;
        }

        public async Task< Page<TEntity>> PageAsync(IQueryable<TEntity> q, BasePageQto qm)
        {
            var Total=await q.CountAsync(); 
            var r=new Page<TEntity>(Total,qm.Page,qm.PageSize);
             
            var l = await q.SortPageTakeAsync(qm.GetSort(), r);
            r.Records = l;
            return r;
        }

 


    }

}
